#include <stdio.h>
#include <bfd.h>
#include <malloc.h>
#include "utils.h"
#include "armdefs.h"

int big_endian = 0;

int load_image(char *file, int name_len)
{
	bfd *tmp_bfd = NULL;
	asection* sec = NULL;


	tmp_bfd = bfd_openr(file, NULL);


	if(tmp_bfd == NULL)
	{
		ARM_Instr_Debug(("Can't open a file : %s\n",file));
		return FILE_OPEN_ERROR;
	}


	if(!bfd_check_format(tmp_bfd,bfd_object)){
		

	}

	big_endian = bfd_big_endian(tmp_bfd);

	for(sec = tmp_bfd->sections; sec ;sec = sec->next){



	} 
}

int check_condition(unsigned int instr)
{

	switch(BITS(instr,28,31))
	{
		case COND_EQ:
		case COND_NE:
		case COND_HS:
		case COND_LO:
		case COND_MI:
		case COND_PL:
		case COND_VS:
		case COND_VC:
		case COND_HI:
		case COND_LS:
		case COND_GE:
		case COND_LT:
		case COND_GT:
		case COND_LE:
    
		break;

		case COND_AL:
			return INSTR_ACCEPTED;

		default:

		break;


	}

}

static inline int classify_Opcode(ARMProcState* Proc)
{

	unsigned int instr = Proc->CurInstr;
	unsigned int Op1 = BITS(instr,25,27);
	// I need to refer a page 208 in an ARM architecture reference manual	
	// table A5-1 ARM instruction encoding

	switch(Op1){ 
		case DATA_PROC_AND_MISC_INSTR1:
		case DATA_PROC_AND_MISC_INSTR2:
			data_proc_and_misc_instruction(Proc);
			ARM_Instr_Debug(("Data_Proc_AND_Misc_INSTR1\n"));
		//Data-processing and miscellaneous instructions

			break;

		case LOAD_STORE_WORD_AND_BYTE_INSTR1:
		// Load/Store word and unsigned byte 
			break;

		case LOAD_STORE_WORD_AND_BYTE_INSTR2:
		//case MEDIA_INSTR:

		// Load/Store word and unsigned byte
		// Media instructions
			break;

		case BRANCH_AND_BRANCH_LINK_INSTR1:
		case BRANCH_AND_BRANCH_LINK_INSTR2:

		//Branch,branch with link and block data transfer
			break;

		case SUPERV_CALL_AND_COPROC_INSTR1:
		case SUPERV_CALL_AND_COPROC_INSTR2:
			break;

		default:
		// exception		
			break;
	}

}

/* function name : data_proc_and_misc_instruction
   parameter :  instr  (current instruction)
   
   I will process the function of instructions which it has a zero in bits from 25th to 27th 
   It can be changed the way for doing it

   refer to A5.2 Data-processing and miscellaneous instructions
*/


int data_proc_and_misc_instruction(ARMProcState *Proc)
{
	unsigned int instr = Proc->CurInstr;
	unsigned int Op1 = BITS(instr,20,24);
	unsigned int Op2 = BITS(instr,4,7);
	unsigned int Op1_parts = 0;
	unsigned int tmp = -1;

	Op1 = Op1 & 0x1f;
	Op2 = Op2 & 0xf;

	switch(BIT(instr,25)){ 

		case 0: 
			 if(0x16 == (Op1 & ((unsigned int)-0x7))){ 
				/* Misc & Halfword multiply and multiply-accumulate instructions  */
				 if(0 == (Op2 & 0x8)){ 
					 /*Miscellaneous instructions On A5-18*/
					 break;
				 }
				 else if(1 == (Op2 & 0x9)){ 
					 /*Halfword multiply and multiply-accumulate on A5-13*/
					 break;
				 }
				 else{
					 /*Exception*/
				 	break;
				 }
			 }
			 else { 
			 	if(0 == (Op2 & 1)){
					/* Data Processing (register) on A5-5 */
					Data_Processing_Instr_reg(Proc);
					ARM_Instr_Debug(("Data Processing instruction reg\n"));
					 break;
			 	}
			 	else if(0x8 == (Op2 &((unsigned int)-0x7))){ 
					/* Data Processing (register-shifted register) on A5-7*/
				    Data_Processing_Instr_Shifted_reg(Proc); 
					 break;
			 	}
				else { 
					/* Exception */
					break;
				}
			}

			if(0x2 == (Op1 & 0x12)){ 
				if(0xb == Op2){
					/*Extra load-store instructions(unprivileged) on A5-15*/
					break;
				}
				else if(0xd == (Op2 & 0xd)){ 
					/*Extra load-store instructions(unprivileged) on A5-15*/
					break;
				}
				else{ 
					/* Exception */
					break;
				}
			}
			else { 
				if(0xd == Op2){ 
					/*Extra load store instructions on A5-14*/
					break;
				}
				else if(0xd == (Op2 & 0xd)){ 
					/*Extra load store instructions on A5-14*/
					break;
				}
				else { 
					/*exception */
					break;
				}
			}

			Op1_parts = BIT(instr,24);
			if(Op1_parts == 0x0){ 
				/*Multiply and multiply-accumulate on A5-12*/
				break;
			}
					
			else if(Op1_parts == 0x1){ 
				/*Synchronization primitives on A5-16*/
				break;
			}

			else { 
				/*Exception */
				break;
			}

			break;


		case 1:
			if(0x10 == Op1){ 
				/*16 bit immediate load (MOV (immediate) on A8-194*/
				break;
			}
			else if(0x14 == Op1){ 
				/*High halfword 16-bit immediate load(MOVT on A8-200)*/
				break;
			}
			else if(0x12 == (Op1 & 0x12)){ 
				/*MSR (immediate) and hints on A5-17*/
				break;
			}
			else if(0x10 != (Op1 & 0x10)){ 
				/*Data-processing(immediate) on A5-8*/
				Data_Processing_Instr_Imm(Proc); 
				break;
			}
			else { 
				/*Exception*/
				break;
			}
			break;


		default:
			/* exception */
			break;
	}


}








int main(void)
{
//	unsigned int aaaa = 0xe1a0c00d;
//	unsigned int aaaa = 0xe0023003;
	unsigned int aaaa = 0xe0121103;

	ARMProcStateList = malloc(sizeof(ARMProcState));

	// load a binary
	// update the ARMProcState structure.

	ARMProcStateList[0].CurInstr = aaaa;
	ARMProcStateList[0].Reg[1] = 1;
	ARMProcStateList[0].Reg[2] = 2;
	ARMProcStateList[0].Reg[3] = 3;



	if(check_condition(aaaa) == INSTR_ACCEPTED)
		printf("%d\n",BITS(aaaa,28,31));	
	classify_Opcode(&ARMProcStateList[0]);

}
